package com.rustic.server.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.xy.base.server.po.SysAdmin;
import cn.xy.base.server.service.SysAdminService;
import cn.xy.commons.constant.Consts;
import cn.xy.commons.enums.DisableStatus;
import cn.xy.commons.exception.JzRuntimeException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rustic.server.dao.FoodDao;
import com.rustic.server.dto.FoodAddDTO;
import com.rustic.server.dto.FoodUpdateDTO;
import com.rustic.server.dto.RestaurantAddDTO;
import com.rustic.server.dto.RestaurantUpdateDTO;
import com.rustic.server.enums.CategoryType;
import com.rustic.server.enums.LinkType;
import com.rustic.server.po.Category;
import com.rustic.server.po.Food;
import com.rustic.server.po.Restaurant;
import com.rustic.server.po.Rustic;
import com.rustic.server.po.UserCollectionLink;
import com.rustic.server.po.UserLikeLink;
import com.rustic.server.query.FoodAdminListQuery;
import com.rustic.server.query.FoodUserListQuery;
import com.rustic.server.service.CategoryService;
import com.rustic.server.service.CommentService;
import com.rustic.server.service.FoodService;
import com.rustic.server.service.RestaurantService;
import com.rustic.server.service.RusticService;
import com.rustic.server.service.UserBrowseLinkService;
import com.rustic.server.service.UserCollectionLinkService;
import com.rustic.server.service.UserLikeLinkService;
import com.rustic.server.vo.FoodVO;
import com.rustic.server.vo.FoodWebVO;
import com.rustic.server.vo.list.FoodAdminListVO;
import com.rustic.server.vo.list.FoodWebListVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Food对应的服务类实现
 *
 * @author auto
 */

@Slf4j
@Service
public class FoodServiceImpl extends ServiceImpl<FoodDao, Food> implements FoodService {

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private RestaurantService restaurantService;

    @Autowired
    private RusticService rusticService;

    @Autowired
    private SysAdminService sysAdminService;

    @Autowired
    private UserLikeLinkService userLikeLinkService;

    @Autowired
    private UserCollectionLinkService userCollectionLinkService;

    @Autowired
    private UserBrowseLinkService userBrowseLinkService;

    @Override
    public List<Food> listByIdIn(List<Integer> idList) {
        if (CollUtil.isEmpty(idList)) {
            return new ArrayList<>();
        }
        return this.listByIds(idList);
    }

    @Override
    public Map<Integer, Food> mapByIdIn(List<Integer> idList) {
        List<Food> foodList = this.listByIdIn(idList);
        return foodList.stream().collect(Collectors.toMap(Food::getId, b -> b));
    }

    @Override
    public LambdaQueryWrapper<Food> toAdminListWrapper(FoodAdminListQuery query) {
        LambdaQueryWrapper<Food> queryWrapper = new LambdaQueryWrapper<>();
        //FIXME 根据需要修改搜索条件
        queryWrapper.eq(Food::getRusticId, query.getRusticId());
        queryWrapper.like(CharSequenceUtil.isNotEmpty(query.getName()), Food::getName, query.getName());
        queryWrapper.eq(query.getCategoryId() > 0, Food::getCategoryId, query.getCategoryId());
        queryWrapper.eq(query.getStatus() > 0, Food::getStatus, query.getStatus());
        queryWrapper.gt(query.getStartPublishTime() != null, Food::getPublishTime, query.getStartPublishTime());
        queryWrapper.lt(query.getEndPublishTime() != null, Food::getPublishTime, query.getEndPublishTime());

        queryWrapper.orderByDesc(Food::getSort);
        queryWrapper.orderByDesc(Food::getUpdateTime);
        return queryWrapper;
    }

    @Override
    public List<FoodAdminListVO> toAdminListVo(List<Food> foodList) {
        List<Category> categoryList = categoryService.listByType(CategoryType.FOOD);
        Map<Integer, Category> categoryMap = categoryList.stream().collect(Collectors.toMap(Category::getId, b -> b));
        List<FoodAdminListVO> results = new ArrayList<>();
        for (Food food : foodList) {
            FoodAdminListVO foodAdminListVO = new FoodAdminListVO(food);
            Category category = categoryMap.get(food.getCategoryId());
            foodAdminListVO.setCategoryName(category != null ? category.getName() : "");
            results.add(foodAdminListVO);
        }
        return results;
    }

    @Override
    public List<FoodWebListVO> toWebListVo(List<Food> foodList, int userId) {
        List<Integer> foodIdList = foodList.stream().map(Food::getId).collect(Collectors.toList());
        Map<Integer, Long> likeCountMap = userLikeLinkService.mapByTargetIdAndType(foodIdList, LinkType.FOOD);
        Map<Integer, Long> collectionCountMap = userCollectionLinkService.mapByTargetIdAndType(foodIdList, LinkType.FOOD);
        Map<Integer, Long> browseCountMap = userBrowseLinkService.mapByTargetIdAndType(foodIdList, LinkType.FOOD);
        // 用户是否有点赞收藏
        Map<Integer, UserLikeLink> userLikeMap = userLikeLinkService.mapByUserTargetAndType(foodIdList, LinkType.FOOD, userId);
        Map<Integer, UserCollectionLink> userCollectionMap = userCollectionLinkService.mapByUserTargetAndType
                (foodIdList, LinkType.FOOD, userId);
        // 查询景点对应的乡村
        List<Integer> rusticIdList = foodList.stream().map(Food::getRusticId).collect(Collectors.toList());
        Map<Integer, Rustic> rusticMap = rusticService.mapByIdIn(rusticIdList);
        return foodList.stream().map(item -> {
            FoodWebListVO foodWebListVO = new FoodWebListVO(item);
            // 得到点赞的数量
            if (likeCountMap.get(item.getId()) != null) {
                foodWebListVO.setLikeCount(likeCountMap.get(item.getId()));
            }
            // 收藏的数量
            if (collectionCountMap.get(item.getId()) != null) {
                foodWebListVO.setCollectionCount(collectionCountMap.get(item.getId()));
            }
            // 浏览数量
            if (browseCountMap.get(item.getId()) != null) {
                foodWebListVO.setBrowseCount(browseCountMap.get(item.getId()));
            }
            // 用户是否点赞
            if (userLikeMap.get(item.getId()) != null) {
                foodWebListVO.setLike(true);
            }
            // 用户是否收藏
            if (userCollectionMap.get(item.getId()) != null) {
                foodWebListVO.setCollection(true);
            }
            // 填充对应的乡村名称
            Rustic rustic = rusticMap.get(item.getRusticId());
            if (rustic != null) {
                foodWebListVO.setRusticName(rustic.getName());
            }
            return foodWebListVO;
        }).collect(Collectors.toList());
    }

    @Override
    public LambdaQueryWrapper<Food> toUserListWrapper(FoodUserListQuery query) {
        LambdaQueryWrapper<Food> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(Food::getId, Food::getRusticId, Food::getName, Food::getCover, Food::getCategoryId,
                Food::getRestaurantIds, Food::getPublishTime, Food::getUpdateTime, Food::getCreateTime);
        queryWrapper.eq(query.getRusticId() > 0, Food::getRusticId, query.getRusticId());
        queryWrapper.like(CharSequenceUtil.isNotEmpty(query.getName()), Food::getName, query.getName());
        queryWrapper.eq(query.getCategoryId() > 0, Food::getCategoryId, query.getCategoryId());
        queryWrapper.eq(Food::getStatus, DisableStatus.NORMAL.getValue());
        queryWrapper.orderByDesc(Food::getSort);
        queryWrapper.orderByDesc(Food::getUpdateTime);
        return queryWrapper;
    }

    private void checkExist(int rusticId, int categoryId) {
        Rustic rustic = rusticService.getById(rusticId);
        if (rustic == null) {
            throw new JzRuntimeException(RusticService.RUSTIC_NOT_EXIST);
        }
        Category category = categoryService.getById(categoryId);
        if (category == null) {
            throw new JzRuntimeException(CategoryService.CATEGORY_NOT_EXIST);
        }
    }

    @Override
    public void add(FoodAddDTO foodAddDTO) {
        this.checkExist(foodAddDTO.getRusticId(), foodAddDTO.getCategoryId());
        List<RestaurantAddDTO> restaurantDTOList = foodAddDTO.getRestaurantList();
        String restaurantIds = "";
        if (CollUtil.isNotEmpty(restaurantDTOList)) {
            List<Restaurant> restaurantList = restaurantDTOList.stream().map(RestaurantAddDTO::toRestaurant).collect(Collectors.toList());
            restaurantService.saveBatch(restaurantList);
            List<Integer> restaurantIdList = restaurantList.stream().map(Restaurant::getId).collect(Collectors.toList());
            restaurantIds = CharSequenceUtil.join(Consts.COMMA, restaurantIdList);
        }

        Food food = foodAddDTO.toFood();
        food.setRestaurantIds(restaurantIds);
        // 直接发布
        food.setStatus(DisableStatus.NORMAL.getValue());
        food.setPublishTime(new Date());
        this.save(food);
    }

    @Override
    public void updateFood(FoodUpdateDTO foodUpdateDTO) {
        this.checkExist(foodUpdateDTO.getRusticId(), foodUpdateDTO.getCategoryId());
        Food food = this.getById(foodUpdateDTO.getId());
        if (food == null) {
            throw new JzRuntimeException(FoodService.FOOD_NOT_EXIST);
        }
        if (CharSequenceUtil.isNotEmpty(food.getRestaurantIds())) {
            List<String> restaurantIdList = CharSequenceUtil.split(food.getRestaurantIds(), Consts.COMMA);
            // 删除原来的餐厅
            restaurantService.removeBatchByIds(restaurantIdList);
        }
        List<RestaurantUpdateDTO> restaurantDTOList = foodUpdateDTO.getRestaurantList();
        String restaurantIds = "";
        if (CollUtil.isNotEmpty(restaurantDTOList)) {
            List<Restaurant> restaurantList = restaurantDTOList.stream().map(RestaurantUpdateDTO::toRestaurant).collect(Collectors.toList());
            restaurantService.saveBatch(restaurantList);
            List<Integer> restaurantIdList = restaurantList.stream().map(Restaurant::getId).collect(Collectors.toList());
            restaurantIds = CharSequenceUtil.join(Consts.COMMA, restaurantIdList);
        }

        Food foodUpdate = foodUpdateDTO.toFood();
        foodUpdate.setRestaurantIds(restaurantIds);
        // 直接发布
        foodUpdate.setStatus(DisableStatus.NORMAL.getValue());
        foodUpdate.setPublishTime(new Date());
        this.updateById(foodUpdate);
    }

    @Override
    public void delete(int id) {
        Food food = this.getById(id);
        if (food == null) {
            throw new JzRuntimeException(FoodService.FOOD_NOT_EXIST);
        }
        if (CharSequenceUtil.isNotEmpty(food.getRestaurantIds())) {
            List<String> restaurantIdList = CharSequenceUtil.split(food.getRestaurantIds(), Consts.COMMA);
            // 删除原来的餐厅
            restaurantService.removeBatchByIds(restaurantIdList);
        }
        this.removeById(id);
    }

    @Override
    public int enabled(int id) {
        Food food = this.getById(id);
        if (food == null) {
            throw new JzRuntimeException(FoodService.FOOD_NOT_EXIST);
        }
        if (DisableStatus.isDisable(food.getStatus())) {
            // 要上架的
            food.setPublishTime(new Date());
        }
        food.setStatus(DisableStatus.negate(food.getStatus()));
        this.updateById(food);
        return food.getStatus();
    }

    @Override
    public FoodVO getDetailById(int id) {
        Food food = this.getById(id);
        if (food == null) {
            throw new JzRuntimeException(FoodService.FOOD_NOT_EXIST);
        }
        FoodVO foodVO = new FoodVO(food);
        if (CharSequenceUtil.isNotEmpty(food.getRestaurantIds())) {
            List<String> restaurantIdList = CharSequenceUtil.split(food.getRestaurantIds(), Consts.COMMA);
            List<Integer> restaurantIds = restaurantIdList.stream()
                    .map(Integer::parseInt)
                    .collect(Collectors.toList());
            List<Restaurant> restaurants = restaurantService.listByIdIn(restaurantIds);
            foodVO.setRestaurantList(restaurants);
        }
        List<Integer> sysAdminListId = new ArrayList<>();
        Collections.addAll(sysAdminListId, food.getCreatorId(), food.getModifierId());
        Map<Integer, SysAdmin> sysAdminMap = sysAdminService.mapByIdList(sysAdminListId);
        foodVO.setModifier(sysAdminMap.get(food.getModifierId()) != null ?
                sysAdminMap.get(food.getModifierId()).getUsername() : "");
        foodVO.setCreator(sysAdminMap.get(food.getCreatorId()) != null ?
                sysAdminMap.get(food.getCreatorId()).getUsername() : "");
        return foodVO;
    }

    @Override
    public FoodWebVO getByIdToWeb(int id) {
        FoodVO foodVO = this.getDetailById(id);
        FoodWebVO foodWebVO = new FoodWebVO(foodVO);
        Rustic rustic = rusticService.getById(foodVO.getRusticId());
        foodWebVO.setRusticName(rustic != null ? rustic.getName() : "");
        // 分类
        List<Category> categoryList = categoryService.listByType(CategoryType.FOOD);
        Map<Integer, Category> categoryMap = categoryList.stream().collect(Collectors.toMap(Category::getId, b -> b));
        foodWebVO.setCategoryName(categoryMap.get(foodVO.getCategoryId()) != null ?
                categoryMap.get(foodVO.getCategoryId()).getName() : "");
        return foodWebVO;
    }


}
